#version 400

// PN patch data
struct PnPatch
{
 float b210;
 float b120;
 float b021;
 float b012;
 float b102;
 float b201;
 float b111;
 float n110;
 float n011;
 float n101;
};

layout(triangles, equal_spacing, ccw) in;

float uTessAlpha = 1.0f;

uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform mat4 normalMatrix;

in vec3 tcNormal[];
in vec3 tcPosition[];
in vec3 tcLightDir[];
in vec3 tcNormal[];
in PnPatch oPnPatch[];

in vec3 tcWireframeColor[];

out vec3 tePosition;
out vec3 teLightDir;
out vec3 teNormal;
out vec3 teVertexNormal;

out vec3 tePatchDistance;
out vec3 color;

out vec3 teWireframeColor;

#define b300    tcPosition[0].xyz
#define b030    tcPosition[1].xyz
#define b003    tcPosition[2].xyz
#define n200    tcNormal[0]
#define n020    tcNormal[1]
#define n002    tcNormal[2]
#define uvw     gl_TessCoord

void main()
{
	//Flat
	/*float u = gl_TessCoord.x, v = gl_TessCoord.y;
    vec3 a = mix(tcPosition[0], tcPosition[1], u);
    vec3 b = mix(tcPosition[0], tcPosition[2], u);
    tePatchDistance = gl_TessCoord;
	tePosition = mix(a, b, v);*/

 vec3 uvwSquared = uvw*uvw;
 vec3 uvwCubed   = uvwSquared*uvw;
 
 // extract control points
 vec3 b210 = vec3(oPnPatch[0].b210, oPnPatch[1].b210, oPnPatch[2].b210);
 vec3 b120 = vec3(oPnPatch[0].b120, oPnPatch[1].b120, oPnPatch[2].b120);
 vec3 b021 = vec3(oPnPatch[0].b021, oPnPatch[1].b021, oPnPatch[2].b021);
 vec3 b012 = vec3(oPnPatch[0].b012, oPnPatch[1].b012, oPnPatch[2].b012);
 vec3 b102 = vec3(oPnPatch[0].b102, oPnPatch[1].b102, oPnPatch[2].b102);
 vec3 b201 = vec3(oPnPatch[0].b201, oPnPatch[1].b201, oPnPatch[2].b201);
 vec3 b111 = vec3(oPnPatch[0].b111, oPnPatch[1].b111, oPnPatch[2].b111);
 
 // extract control normals
 vec3 n110 = normalize(vec3(oPnPatch[0].n110,
                            oPnPatch[1].n110,
                            oPnPatch[2].n110));

 vec3 n011 = normalize(vec3(oPnPatch[0].n011,
                            oPnPatch[1].n011,
                            oPnPatch[2].n011));

 vec3 n101 = normalize(vec3(oPnPatch[0].n101,
                            oPnPatch[1].n101,
                            oPnPatch[2].n101));
 

 // compute texcoords
 /*oTexCoord  = gl_TessCoord[2]*iTexCoord[0]
            + gl_TessCoord[0]*iTexCoord[1]
            + gl_TessCoord[1]*iTexCoord[2];
 */

 
 // normal
 vec3 barNormal = gl_TessCoord[2]*tcNormal[0]
                + gl_TessCoord[0]*tcNormal[1]
                + gl_TessCoord[1]*tcNormal[2];
 
 vec3 pnNormal  = n200*uvwSquared[2]
                + n020*uvwSquared[0]
                + n002*uvwSquared[1]
                + n110*uvw[2]*uvw[0]
                + n011*uvw[0]*uvw[1]
                + n101*uvw[2]*uvw[1];

 teNormal = uTessAlpha*pnNormal + (1.0-uTessAlpha)*barNormal;
 //not sure
 teLightDir = vec3(gl_TessCoord[2]*tcLightDir[0] + gl_TessCoord[0]*tcLightDir[1] + gl_TessCoord[1]*tcLightDir[2]);
 
 // compute interpolated pos
 vec3 barPos = gl_TessCoord[2]*b300
             + gl_TessCoord[0]*b030
             + gl_TessCoord[1]*b003;
 
 // save some computations
 uvwSquared *= 3.0;
 
 // compute PN position
 vec3 pnPos  = b300*uvwCubed[2]
             + b030*uvwCubed[0]
             + b003*uvwCubed[1]
             + b210*uvwSquared[2]*uvw[0]
             + b120*uvwSquared[0]*uvw[2]
             + b201*uvwSquared[2]*uvw[1]
             + b021*uvwSquared[0]*uvw[1]
             + b102*uvwSquared[1]*uvw[2]
             + b012*uvwSquared[1]*uvw[0]
             + b111*6.0*uvw[0]*uvw[1]*uvw[2];
 
 // final position and normal
 vec3 finalPos = (1.0-uTessAlpha)*barPos + uTessAlpha*pnPos;
 //vec3 finalPos = barPos;
 gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(finalPos,1.0);

 tePatchDistance = gl_TessCoord;
 tePosition = finalPos;
 teWireframeColor = vec3(tcWireframeColor[0]);
 
 /*
	vec3 p0 = gl_TessCoord.x * tcPosition[0];
    vec3 p1 = gl_TessCoord.y * tcPosition[1];
    vec3 p2 = gl_TessCoord.z * tcPosition[2];
	
	tePatchDistance = gl_TessCoord;
	tePosition = vec3(p0 + p1 + p2);
	teVertexNormal = vec3( tcNormal[0] + tcNormal[1] + tcNormal[2]);
	


	//weight of each vertex normal of the original polygon
	teNormal = normalize(normalize(tcNormal[0])*gl_TessCoord.x + normalize(tcNormal[1])*gl_TessCoord.y + normalize(tcNormal[2])*gl_TessCoord.z);
	float weightP0 = 1.0-dot(tcNormal[0], p0 - tePosition/3);
	float weightP1 = 1.0-dot(tcNormal[1], p1 - tePosition/3);
	float weightP2 = 1.0-dot(tcNormal[2], p2 - tePosition/3);
	
	//Length of active vertex (new or old) to center of triangle (0.5, 0.5, 0.5)
	float normalWeight = - length(vec3(0.5, 0.5, 0.5) - gl_TessCoord.xyz) +1.0f;

	color = vec3(1,1,1);// vec3(weight, weight, weight);
	/*if(gl_TessCoord.z == 1 || gl_TessCoord.z == 0)
		gl_Position = projectionMatrix * viewMatrix * modelMatrix * ( vec4(tePosition.xy, normalWeight, 1));
	else*/
	//gl_Position = projectionMatrix * viewMatrix * modelMatrix * ( vec4(tePosition, 1) + 0.02*normalWeight*normalMatrix*vec4(teNormal, 1));
	//gl_Position = projectionMatrix * viewMatrix * modelMatrix * ( vec4(tePosition, 1) +0.0f*vec4(teNormal, 1));


	/*vec3 p0 = gl_in[0].gl_Position.xyz;
    vec3 p1 = gl_in[1].gl_Position.xyz;
    vec3 p2 = gl_in[2].gl_Position.xyz;*/
	/*vec3 p0 = gl_TessCoord.x * tcPosition[0];
    vec3 p1 = gl_TessCoord.y * tcPosition[1];
    vec3 p2 = gl_TessCoord.z * tcPosition[6];
	


	tePatchDistance = gl_TessCoord;

	tePosition = vec3(p0 + p1 + p2);
	//tePosition = normalize(p0 + p1 + p2);

	gl_Position = projectionMatrix * viewMatrix * modelMatrix *  vec4(tePosition, 1);
  */
	/*
	gl_Position = vec4(gl_in[0].gl_Position.xyz * gl_TessCoord.x + 
					   gl_in[1].gl_Position.xyz * gl_TessCoord.y + 
					   gl_in[2].gl_Position.xyz * gl_TessCoord.z,
					   1.0);
					   */
}